package com.jk.tweetsnear.fragment;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import twitter4j.GeoLocation;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.conf.ConfigurationBuilder;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import android.text.SpannableString;
import android.util.Log;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.BounceInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.analytics.tracking.android.GoogleAnalytics;
import com.google.analytics.tracking.android.Tracker;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.jk.tweetsnear.MainActivity;
import com.jk.tweetsnear.R;
import com.jk.tweetsnear.application.App;
import com.jk.tweetsnear.data.TweetData;
import com.jk.tweetsnear.utils.Const;
import com.jk.tweetsnear.utils.Utils;

public class TweetMapFragment extends SupportMapFragment implements OnMarkerClickListener, OnInfoWindowClickListener, OnCameraChangeListener
{
	public final String TAG = getClass().getSimpleName() + Utils.TAG_OPTION;

	private static View view;
	
	private GoogleMap googleMap;
	private HashMap<String, TweetData> hashMapMarker = new HashMap<String, TweetData>();
	private ArrayList<Marker> arrayMarker = new ArrayList<Marker>();
	private ProgressDialog progDialog;
	private AsyncGetGeo getGeo;
	private Tracker mGaTracker;
	private GoogleAnalytics mGaInstance;		
	
	private ImageView ivNextTweet;
	private ImageView ivPrevTweet;
	private ImageView ivRefresh;
	
	private int markerPosition;
	private boolean newLocation;
	private double newLat;
	private double newLon;
	
	private final int ALREADY_FOLLOWING = 10;
	private final int FOLLOWING = 11;
	
	@Override
	public void onStart()
	{
		super.onStart();
		mGaTracker.sendView("/TweetMapFragment");
	}		
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
	{
		// SupportMapFragment 쓸때 필요
		super.onCreateView(inflater, container, savedInstanceState);

		if (Utils.DEBUG)
			Log.e(Utils.FILLTER, TAG + "onCreateView...");	
		
		mGaInstance = GoogleAnalytics.getInstance(App.act);
		mGaTracker = mGaInstance.getTracker(Utils.TRACKER_ID); 			
		
		if (view != null)
		{
			ViewGroup parent = (ViewGroup) view.getParent();
			if (parent != null)
			{
				parent.removeView(view);
			}
		}
		try
		{
			view = inflater.inflate(R.layout.tweet_map_fragment, null);
		} catch (InflateException e)
		{
			// 맵이 이미 생성되어 있음 , 뷰를 그냥 리턴 하면 된다.
			if (Utils.DEBUG)
				Log.e(Utils.FILLTER, TAG + "onCreateView view already created...");
			
			return view;
		}
		
		setWidJet(view);
		
		setUpMapIfNeeded();
		
		return view;
	}
	
	private void setWidJet(View view)
	{
		ivNextTweet = (ImageView) view.findViewById(R.id.iv_nextTweet);
		ivPrevTweet = (ImageView) view.findViewById(R.id.iv_prevTweet);
		ivRefresh = (ImageView) view.findViewById(R.id.iv_refresh);
		
		ivNextTweet.setOnClickListener(onClick);
		ivPrevTweet.setOnClickListener(onClick);
		ivRefresh.setOnClickListener(onClick);
	}
	
	Handler handler = new Handler()
	{
		@Override
		public void handleMessage(Message msg)
		{
			String targetScreenName = (String) msg.obj;			
			
			switch (msg.what)
			{
			case 0:
				MainActivity.arrayTweetData.clear();
				hashMapMarker.clear();
				arrayMarker.clear();
				googleMap.clear();
				googleMap = null;
				
				getGeo = new AsyncGetGeo();
				getGeo.execute();				
				break;
			case ALREADY_FOLLOWING:
				mGaTracker.sendEvent("ui_action", "button_press", "twitter_map_already_following", 0L);				
				
				Utils.showAlreadyFollowingAlert(App.act, targetScreenName);
				break;
			case FOLLOWING:
				mGaTracker.sendEvent("ui_action", "button_press", "twitter_map_following", 0L);				
				
				Utils.showFollowingAlert(App.act, targetScreenName);
				break;				
			}
			
			super.handleMessage(msg);			
		}
	};
	
	OnClickListener onClick = new OnClickListener()
	{
		@Override
		public void onClick(View v)
		{
			switch (v.getId())
			{
			case R.id.iv_nextTweet:
				mGaTracker.sendEvent("ui_action", "button_press", "twitter_map_next", 0L);					
				
				if (markerPosition < MainActivity.arrayTweetData.size() - 1)
					markerPosition++;
				else
					markerPosition = 0;

				break;
			case R.id.iv_prevTweet:
				mGaTracker.sendEvent("ui_action", "button_press", "twitter_map_prev", 0L);					
				
				if (markerPosition == 0)
					markerPosition = MainActivity.arrayTweetData.size() - 1;
				else
					markerPosition--;
				break;
			case R.id.iv_refresh:
				mGaTracker.sendEvent("ui_action", "button_press", "twitter_map_refresh", 0L);				
				
				newLocation = true;
				
				Message msgNewLocation = new Message();				
				msgNewLocation.what = 0;
				handler.sendMessage(msgNewLocation);
				break;	
			}
			
			if(newLocation == false)
			{
				Marker marker = arrayMarker.get(markerPosition);
				animateMarker(marker);
				CameraPosition camPos = new CameraPosition.Builder().target(marker.getPosition()).zoom(googleMap.getCameraPosition().zoom).bearing(0).tilt(0).build();
				googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(camPos));
				marker.showInfoWindow();	
			}
		}
	};

	private void setUpMapIfNeeded()
	{
		if (googleMap == null)
		{
			googleMap = ((SupportMapFragment) ((FragmentActivity) App.act).getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
			if (googleMap != null)
			{
				setUpMap();
			}
		}  else
			setUpMap();
	}
	
	private void setUpMap()
	{
		addMarker();

		googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());

		googleMap.setOnMarkerClickListener(this);
		googleMap.setOnInfoWindowClickListener(this);
		googleMap.setMyLocationEnabled(true);
		googleMap.setOnCameraChangeListener(this);
		

		// Pan to see all markers in view.
		// Cannot zoom to bounds until the map has a size.
		final View mapView = ((FragmentActivity) App.act).getSupportFragmentManager().findFragmentById(R.id.map).getView();
		
		if (Utils.DEBUG)
			Log.e(Utils.FILLTER, TAG + " isAlive : " + mapView.getViewTreeObserver().isAlive());		
		
		
		if (mapView.getViewTreeObserver().isAlive())
		{
			mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
			{
				@SuppressWarnings("deprecation")
				// We use the new method when supported
				@SuppressLint("NewApi")
				// We check which build version we are using.
				@Override
				public void onGlobalLayout()
				{
					//LatLngBounds bounds = new LatLngBounds.Builder().include(PERTH).include(SYDNEY).include(ADELAIDE).include(BRISBANE).include(MELBOURNE).build();
					LatLngBounds.Builder bounds = new LatLngBounds.Builder();   
					for (int i = 0; i < MainActivity.arrayTweetData.size(); i++)
					{
						bounds.include(new LatLng(MainActivity.arrayTweetData.get(i).getLat() , MainActivity.arrayTweetData.get(i).getLon()));
					}
					
					if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
					{
						mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
					} else
					{
						mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
					}
					googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 50));
				}
			});
		}
	}	
	
	private void addMarker()
	{
		try
		{
			
			if (Utils.DEBUG)
				Log.e(Utils.FILLTER, TAG + "addMarker tweet size = " + MainActivity.arrayTweetData.size());					
			
			Marker marker = null;
			googleMap.clear();
			
			for (int i = 0; i < MainActivity.arrayTweetData.size(); i++)
			{
				LatLng markerPostion = new LatLng(MainActivity.arrayTweetData.get(i).getLat(), MainActivity.arrayTweetData.get(i).getLon());
				marker = googleMap.addMarker(new MarkerOptions().position(markerPostion).icon(BitmapDescriptorFactory.defaultMarker(i * 360 / MainActivity.arrayTweetData.size())));
				hashMapMarker.put(marker.getId(), MainActivity.arrayTweetData.get(i));
				arrayMarker.add(i, marker);
			}			

		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public void onResume()
	{
		super.onResume();

	}

	@Override
	public void onInfoWindowClick(Marker marker)
	{
		new AsyncWaiting().execute(marker);
	}

	@Override
	public boolean onMarkerClick(final Marker marker)
	{
		animateMarker(marker);
		return false;
	}
	
	private void animateMarker(final Marker marker)
	{
		final Handler handler = new Handler();
		final long start = SystemClock.uptimeMillis();
		final long duration = 1300;

		final Interpolator interpolator = new BounceInterpolator();

		handler.post(new Runnable()
		{
			@Override
			public void run()
			{
				long elapsed = SystemClock.uptimeMillis() - start;
				float t = Math.max(1 - interpolator.getInterpolation((float) elapsed / duration), 0);
				marker.setAnchor(0.5f, 1.5f * t);

				if (t > 0.0)
				{
					handler.postDelayed(this, 10);
				}
			}
		});		
	}
	
	
	class CustomInfoWindowAdapter implements InfoWindowAdapter
	{
		private final View mWindow;
		private final View mContents;

		CustomInfoWindowAdapter()
		{
			mWindow = App.act.getLayoutInflater().inflate(R.layout.custom_info_window, null);
			mContents = App.act.getLayoutInflater().inflate(R.layout.custom_info_contents, null);
		}

		@Override
		public View getInfoWindow(Marker marker)
		{
			if (Utils.DEBUG)
				Log.v(Utils.FILLTER, TAG + "getInfoWindow...");			
			
			render(marker, mWindow);
			return mWindow;
		}

		@Override
		public View getInfoContents(Marker marker)
		{
//			render(marker, mContents);
//			return mContents;
			
			if (Utils.DEBUG)
				Log.v(Utils.FILLTER, TAG + "getInfoContents...");				
			
			return null;
		}

		private void render(Marker marker, View view)
		{
			if (Utils.DEBUG)
				Log.v(Utils.FILLTER, TAG + "marker id : " + marker.getId() );
			
			TweetData mapItem = (TweetData) hashMapMarker.get(marker.getId());
			
			try
			{
				Bitmap.Config conf = Bitmap.Config.ARGB_8888;
				Bitmap bmp = Bitmap.createBitmap(80, 80, conf);
				Bitmap copyBitmap = bmp.copy(Bitmap.Config.ARGB_8888, true);
				
				String title = null;
				String snippet = null;
				String screenName = null;
				String createAt = null;
				
				if (Utils.DEBUG)
					Log.e(Utils.FILLTER, TAG + "click marker tweet size = " + MainActivity.arrayTweetData.size());

				if (Utils.DEBUG)
					Log.e(Utils.FILLTER, TAG + "markerId = " + marker.getId());

				// url 로 이미지 얻어옴
				URL url = new URL(mapItem.getProfileUrl());
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setDoInput(true);
				conn.connect();
				InputStream is = conn.getInputStream();
				copyBitmap = BitmapFactory.decodeStream(is);

				title = mapItem.getName();
				snippet = mapItem.getText();
				screenName = "@"+mapItem.getScreenName();
				createAt = mapItem.getCreateTime();
				
				((ImageView) view.findViewById(R.id.badge)).setImageBitmap(copyBitmap);		
				
				
				TextView titleUi = ((TextView) view.findViewById(R.id.title));
				if (title != null)
				{
					SpannableString titleText = new SpannableString(title);
					//titleText.setSpan(new ForegroundColorSpan(Color.BLACK), 0, titleText.length(), 0);
					titleUi.setText(titleText);
				} else
				{
					titleUi.setText("");
				}
				
				TextView screenNameUi = ((TextView) view.findViewById(R.id.screenName));
				if (screenName != null)
				{
					SpannableString screenNameText = new SpannableString(screenName);
					//screenNameText.setSpan(new ForegroundColorSpan(Color.GRAY), 0, screenNameText.length(), 0);
					screenNameUi.setText(screenNameText);
				} else
				{
					screenNameUi.setText("");
				}
				

				TextView snippetUi = ((TextView) view.findViewById(R.id.snippet));
				if (snippet != null )
				{
					SpannableString snippetText = new SpannableString(snippet);
					//snippetText.setSpan(new ForegroundColorSpan(R.color.kakaotalk_blue), 0, 10, 0);
					snippetUi.setText(snippetText);
				} else
				{
					snippetUi.setText("");
				}	
				
				TextView createAtUi = ((TextView) view.findViewById(R.id.createAt));
				if (createAt != null)
				{
					SpannableString createAtText = new SpannableString(createAt);
					//createAtText.setSpan(new ForegroundColorSpan(Color.GRAY), 0, createAtText.length(), 0);
					createAtUi.setText(createAtText);
				} else
				{
					createAtUi.setText("");
				}				
				
			} catch (Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	private class AsyncGetGeo extends AsyncTask<Void, Void, Void>
	{
		private TweetData data;

		@Override
		protected void onPreExecute()
		{
			super.onPreExecute();
			if (progDialog == null)
			{
				progDialog = new ProgressDialog(App.act);
			}
			progDialog.setMessage("please wait...");
			progDialog.setCancelable(false);
			progDialog.show();
			
			if(newLocation == false)
				Utils.getCurrentLocation(App.act);
		}

		protected Void doInBackground(Void... params)
		{
			int i = 0;

			ConfigurationBuilder builder = new ConfigurationBuilder();
			builder.setOAuthConsumerKey(Const.CONSUMER_KEY);
			builder.setOAuthConsumerSecret(Const.CONSUMER_SECRET);

			String access_token = App.sharedPreferences.getString(Const.PREF_KEY_OAUTH_TOKEN, "");
			String access_token_secret = App.sharedPreferences.getString(Const.PREF_KEY_OAUTH_SECRET, "");

			AccessToken accessToken = new AccessToken(access_token, access_token_secret);
			App.twitter = new TwitterFactory(builder.build()).getInstance(accessToken);

			Query query = new Query();
			query.count(50);
			
			if(Utils.DEBUG)
			{
				Log.v(Utils.FILLTER, TAG + " cameraPosition lat : " + newLat);
				Log.v(Utils.FILLTER, TAG + " cameraPosition lon : " + newLon);
				Log.v(Utils.FILLTER, TAG + " newLocation : " + newLocation);
			}			
			
			if(newLocation)
				query.setGeoCode(new GeoLocation(newLat, newLon), 1, Query.KILOMETERS);
			else
				query.setGeoCode(new GeoLocation(App.currentLat, App.currentLon), 1, Query.KILOMETERS);

			
			if(Utils.DEBUG)
			{
				Log.d(Utils.FILLTER, TAG + " cameraPosition lat : " + newLat);
				Log.d(Utils.FILLTER, TAG + " cameraPosition lon : " + newLon);
			}				
			
			QueryResult result = null;

			try
			{
				result = App.twitter.search(query);
			} catch (TwitterException e1)
			{
				e1.printStackTrace();
			}

			if (Utils.DEBUG)
				Log.e(Utils.FILLTER, TAG + " tweet count : " + result.getCount());

			do
			{
				if (result.getCount() != 0)
				{

					for (twitter4j.Status status : result.getTweets())
					{

						if (i == MainActivity.TWEET_COUNT)
							break;

						if (status.getGeoLocation() != null)
						{
							data = new TweetData();

							if (Utils.DEBUG)
							{
								Log.i(Utils.FILLTER, "===============================================================");
								Log.i(Utils.FILLTER, TAG + " @" + status.getUser().getScreenName() + ":" + status.getText());
								Log.i(Utils.FILLTER, TAG + " lon : " + status.getGeoLocation().getLongitude() + ", lat : " + status.getGeoLocation().getLatitude());
								Log.i(Utils.FILLTER, TAG + " name : " + status.getUser().getName());
								Log.i(Utils.FILLTER, TAG + " profileImageUrl : " + status.getUser().getOriginalProfileImageURL());
								Log.i(Utils.FILLTER, TAG + " create time : " + status.getCreatedAt().toString());
							}

							data.setLat(status.getGeoLocation().getLatitude());
							data.setLon(status.getGeoLocation().getLongitude());
							data.setName(status.getUser().getName());
							data.setScreenName(status.getUser().getScreenName());
							data.setText(status.getText());
							data.setProfileUrl(status.getUser().getProfileImageURL());
							data.setCreateTime(Utils.compateCreatedAt(status));

							MainActivity.arrayTweetData.add(i, data);

							i++;
						}
					}

					break;

				} else
				{
					if (Utils.DEBUG)
						Log.i(Utils.FILLTER, TAG + "tweets location is 0...");
				}

			} while ((query = result.nextQuery()) != null);

			if (Utils.DEBUG)
				Log.e(Utils.FILLTER, TAG + "tweet size = " + MainActivity.arrayTweetData.size());

			return null;
		}

		@Override
		protected void onPostExecute(Void result)
		{
			setUpMapIfNeeded();						
			newLocation = false;
			
			progDialog.dismiss();
			
			if(MainActivity.arrayTweetData.size() == 0)
				Toast.makeText(App.act, "sorry no tweets..", Toast.LENGTH_LONG).show();			

			if (Utils.DEBUG)
				Log.i(Utils.FILLTER, TAG + "onPostExecute...");

			super.onPostExecute(result);
		}
	}
	
    private class AsyncWaiting extends AsyncTask<Marker, Void, Void> {

		@Override
		protected void onPreExecute()
		{
			super.onPreExecute();
			if (progDialog == null)
			{
				progDialog = new ProgressDialog(App.act);
			}
			progDialog.setMessage("please wait...");
			progDialog.setCancelable(false);
			progDialog.show();
		}
    	
        @Override
        protected Void doInBackground(Marker... marker) {
    		if(App.twitter != null)
    		{
    			try
    			{
    				TweetData mapItem = (TweetData) hashMapMarker.get(marker[0].getId());
    				
    				String targetScreenName = mapItem.getScreenName();
    				boolean isFollowing = App.twitter.showFriendship(App.twitter.getScreenName(), targetScreenName).isSourceFollowingTarget();
					if(isFollowing)
					{
						Message msg = new Message();
						msg.what = ALREADY_FOLLOWING;
						msg.obj = targetScreenName;
						handler.sendMessage(msg);
					} else 
					{
						Message msg = new Message();
						msg.what = FOLLOWING;
						msg.obj = targetScreenName;
						handler.sendMessage(msg);						
					}
    				
    			} catch (Exception e)
    			{
    				e.printStackTrace();
    			}
    		}
        	
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {

        	progDialog.dismiss();
        	
            super.onPostExecute(result);
        }
    }

	@Override
	public void onCameraChange(CameraPosition position)
	{
		newLat = position.target.latitude;
		newLon = position.target.longitude;
		
		if(Utils.DEBUG)
		{
			Log.e(Utils.FILLTER, TAG + " cameraPosition lat : " + newLat);
			Log.e(Utils.FILLTER, TAG + " cameraPosition lon : " +newLon);
		}
	}	
	
}